package pkg

import (
	"context"
	"encoding/json"
	"mini-app/config"
	"os"
	"time"

	"192.168.1.75/go-pkg/errorx"
	"192.168.1.75/go-pkg/logx"
	"github.com/go-pay/gopay"
	wechatv3 "github.com/go-pay/gopay/wechat/v3"
)

const (
	Success = 0
)

type WechatPay struct{}

var (
	WechatClientV3 *wechatv3.ClientV3
)

// 微信V3初始化
func (wp WechatPay) V3ConfigInit(MchId, SerialNo, APIv3Key string) (err error) {

	// NewClientV3 初始化微信客户端 V3
	//	mchid：商户ID
	// 	serialNo：商户证书的证书序列号
	//	apiV3Key：APIv3Key，商户平台获取
	//	privateKey：商户API证书下载后，私钥 apiclient_key.pem 读取后的字符串内容
	if MchId == "" {
		MchId = config.Config.WechatV3Config.MchID
	}
	if SerialNo == "" {
		SerialNo = config.Config.WechatV3Config.SerialNo
	}
	if APIv3Key == "" {
		APIv3Key = config.Config.WechatV3Config.APIv3Key
	}
	logx.Info(context.Background(), "wechat V3ConfigInit", logx.Any("MchId", MchId), logx.Any("SerialNo", SerialNo), logx.Any("APIv3Key", APIv3Key))

	PrivateKeyContent, _ := os.ReadFile(config.Config.WechatV3Config.ApiclientKey)
	logx.Info(context.Background(), "wechat V3ConfigInit", logx.Any("PrivateKeyContent", PrivateKeyContent), logx.Any("config.Config.WechatV3Config.ApiclientKey", config.Config.WechatV3Config.ApiclientKey))
	WechatClientV3, err = wechatv3.NewClientV3(MchId, SerialNo, APIv3Key, string(PrivateKeyContent))
	if err != nil {
		logx.Info(context.Background(), "wechat V3ConfigInit", logx.Any("err", err))
		return
	}
	logx.Info(context.Background(), "wechat V3ConfigInit", logx.Any("WechatClientV3", WechatClientV3))

	// 打开Debug开关，输出日志
	WechatClientV3.DebugSwitch = gopay.DebugOff
	return nil
}

type WechatNativePayRsp struct {
	ReturnCode string `json:"return_code"`
	ReturnMsg  string `json:"return_msg"`
	Appid      string `json:"appid"`
	SubAppid   string `json:"sub_appid"`
	MchId      string `json:"mch_id"`
	SubMchId   string `json:"sub_mch_id"`
	DeviceInfo string `json:"device_info"`
	NonceStr   string `json:"nonce_str"`
	Sign       string `json:"sign"`
	ResultCode string `json:"result_code"`
	ErrCode    string `json:"err_code"`
	ErrCodeDes string `json:"err_code_des"`
	TradeType  string `json:"trade_type"`
	PrepayId   string `json:"prepay_id"`
	CodeUrl    string `json:"code_url"`
	MwebUrl    string `json:"mweb_url"`
	Timestamp  string `json:"timestamp"`
	PaySign    string `json:"paySign"`
}

// V3TransactionJsapi js下单返回jsapi参数
func (wp WechatPay) V3TransactionJsapi(ctx context.Context, outTradeNo string, totalAmount int64, openid, attach string) (jsapi *wechatv3.JSAPIPayParams, err error) {
	notifyURL := config.Config.BaseUrl + "/mini-app/web/pay/wechat-v3-notify" //回调地址 不能携带参数
	logx.Info(context.Background(), "wechat V3TransactionJsapi", logx.Any("outTradeNo", outTradeNo), logx.Any("notifyURL", notifyURL))
	expire := time.Now().Add(10 * time.Minute).Format(time.RFC3339)
	if len(attach) > 128 {
		err = errorx.New("附加参数最大128字符", -1)
		return
	}
	logx.Info(context.Background(), "wechat V3TransactionJsapi", logx.Any("2", ""))

	bm := make(gopay.BodyMap)
	bm.Set("appid", config.Config.WechatMini.AppID).
		Set("out_trade_no", outTradeNo).
		Set("description", "大道智创小程序下单").
		Set("time_expire", expire).
		Set("notify_url", notifyURL).
		Set("attach", attach). //附加参数 最大128字符
		SetBodyMap("amount", func(bm gopay.BodyMap) {
			bm.Set("total", totalAmount).
				Set("currency", "CNY")
		}).
		SetBodyMap("payer", func(bm gopay.BodyMap) {
			bm.Set("openid", openid)
		})

	logx.Info(context.Background(), "wechat V3TransactionJsapi", logx.Any("3", ""), logx.Any("WechatClientV3", WechatClientV3), logx.Any("bm", bm))

	wxRsp, err1 := WechatClientV3.V3TransactionJsapi(ctx, bm)
	if err1 != nil {
		logx.Info(context.Background(), "wechat V3TransactionJsapi", logx.Any("31", ""))
		err = err1
		return
	}
	logx.Info(context.Background(), "wechat V3TransactionJsapi", logx.Any("4", ""))
	if wxRsp.Error != "" {
		var wxErr struct {
			Code    string `json:"code"`    // "INVALID_REQUEST"
			Message string `json:"message"` // "201 商户订单号重复"
		}
		json.Unmarshal([]byte(wxRsp.Error), &wxErr)
		err = errorx.New(wxErr.Message, -1)
		return
	}
	logx.Info(context.Background(), "wechat V3TransactionJsapi", logx.Any("5", ""))
	if wxRsp.Code == 0 {
		rsp, err := WechatClientV3.PaySignOfJSAPI(config.Config.WechatMini.AppID, wxRsp.Response.PrepayId)
		return rsp, err
	}
	return
}

func (wp WechatPay) V3TransactionJsapiForAdvertisement(ctx context.Context, outTradeNo, openid string, totalAmount int64, attach string) (jsapi *wechatv3.JSAPIPayParams, err error) {
	notifyURL := config.Config.BaseUrl + "/mini-app/advertisement/wechat-v3-notify" //回调地址 不能携带参数
	logx.Info(context.Background(), "wechat V3TransactionJsapi", logx.Any("outTradeNo", outTradeNo), logx.Any("notifyURL", notifyURL))
	expire := time.Now().Add(10 * time.Minute).Format(time.RFC3339)
	if len(attach) > 128 {
		err = errorx.New("附加参数最大128字符", -1)
		return
	}

	bm := make(gopay.BodyMap)
	bm.Set("appid", config.Config.WechatMiniAdvertisement.AppID).
		Set("out_trade_no", outTradeNo).
		Set("description", "大道智创小程广告下单").
		Set("time_expire", expire).
		Set("notify_url", notifyURL).
		Set("attach", attach). //附加参数 最大128字符
		SetBodyMap("amount", func(bm gopay.BodyMap) {
			bm.Set("total", totalAmount).
				Set("currency", "CNY")
		}).
		SetBodyMap("payer", func(bm gopay.BodyMap) {
			bm.Set("openid", openid)
		})

	wxRsp, err1 := WechatClientV3.V3TransactionJsapi(ctx, bm)
	if err1 != nil {
		logx.Info(context.Background(), "wechat V3TransactionJsapi", logx.Any("err1", ""))
		err = err1
		return
	}
	if wxRsp.Error != "" {
		logx.Info(context.Background(), "wechat V3TransactionJsapi", logx.Any("wxRsp.Error", wxRsp.Error))
		var wxErr struct {
			Code    string `json:"code"`    // "INVALID_REQUEST"
			Message string `json:"message"` // "201 商户订单号重复"
		}
		json.Unmarshal([]byte(wxRsp.Error), &wxErr)
		err = errorx.New(wxErr.Message, -1)
		return
	}
	logx.Info(context.Background(), "wechat V3TransactionJsapi", logx.Any("wxRsp.Code", wxRsp.Code))
	if wxRsp.Code == 0 {
		rsp, err := WechatClientV3.PaySignOfJSAPI(config.Config.WechatMiniAdvertisement.AppID, wxRsp.Response.PrepayId)
		return rsp, err
	}
	return
}

// V3TransactionQueryOrder v3订单查询接口
func (wp WechatPay) V3TransactionQueryOrder(ctx context.Context, outTradeNo string) (wxRsp wechatv3.QueryOrderRsp, err error) {
	res, err := WechatClientV3.V3TransactionQueryOrder(ctx, 2, outTradeNo)
	return *res, err
}

// V3CloseOrder v3关闭订单
func (wp WechatPay) V3CloseOrder(ctx context.Context, outTradeNo string) (wxRsp wechatv3.CloseOrderRsp, err error) {
	res, err := WechatClientV3.V3TransactionCloseOrder(ctx, outTradeNo)
	return *res, err
}

// V3Refund V3退款
func (wp WechatPay) V3Refund(ctx context.Context, outTradeNo, outRefundNo string, totalAmount, refundAmount int64) (rsp wechatv3.RefundRsp, err error) {
	bm := make(gopay.BodyMap)
	bm.Set("out_trade_no", outTradeNo).
		Set("out_refund_no", outRefundNo).
		SetBodyMap("amount", func(bm gopay.BodyMap) {
			bm.Set("refund", refundAmount).
				Set("total", totalAmount).
				Set("currency", "CNY")
		})

	res, err := WechatClientV3.V3Refund(ctx, bm)
	return *res, err
}
